import React, { useState, useEffect } from 'react';
import './App.css';
import { pageInfo } from './page/pageStore';
import Monitor from './monitor';
import Page from './page'
const MAX_PAGE = pageInfo.pageList.length - 1;
const MIN_SPEED = 0.0001;
const ANIME_TIME = 1500;
let touchInfo = {};
let scrollTimer;
let scrollToTimer;
let animationID;
function App() {
    const [page, setPage] = useState(0);
    const [pageHeight, setHeight] = useState(0);
    const [scroll, setScroll] = useState(window.scrollY);
    useState(() => {
        setHeight(document.documentElement.clientHeight);
    })
    const onResize = () => {
        //更改窗口尺寸
        setHeight(document.documentElement.clientHeight);
    }
    const onKeyDown = e => {
        if (e.path[0].nodeName === 'INPUT' || e.path[0].nodeName === 'TEXTAREA') return
        switch (e.key) {
            case 'ArrowLeft':
            case 'ArrowUp':
                goPage(page - 1);
                break;
            case 'ArrowRight':
            case 'ArrowDown':
                goPage(page + 1);
                break;
            default:

        }
    }
    const onScroll = () => {
        const disPage = Math.floor(window.scrollY / pageHeight + 0.5);
        setScroll(window.scrollY);
        if (disPage !== page) {
            setPage(disPage);
        }
    }
    const onWheel = e => {
        if (scrollTimer) {
            window.clearTimeout(scrollTimer);
            scrollTimer = null;
        }
        if (animationID) {
            window.cancelAnimationFrame(animationID);
            animationID = null;
        }
        const disPage = Math.floor(window.scrollY / pageHeight + 0.5);
        if (disPage !== page) {
            setPage(disPage);
        }
        scrollTimer = window.setTimeout(() => {
            const targetPage = Math.floor(window.scrollY / pageHeight + 0.5);
            goPage(targetPage)
        }, 500)
    }
    const touchStart = e => {
        if (!touchInfo.active) {
            animationID && window.cancelAnimationFrame(animationID);
            const { y } = getTouchInfo(e);
            setTouch({
                curY: y,
                oriY: y,
                oriPage: page,
                speed: 0,
                active: true
            })
        }
    }
    const touchMove = e => {
        e.preventDefault();
        if (touchInfo.active) {
            const { y } = getTouchInfo(e);
            if (Math.abs(y - touchInfo.oriY) > pageHeight / 2) {
                if (y > touchInfo.oriY) goPage(touchInfo.oriPage - 1)
                if (y < touchInfo.oriY) goPage(touchInfo.oriPage + 1)
                clearTouchInfo();
                return;
            }
            window.scrollBy(0, touchInfo.curY - y)
            setTouch({
                curY: y,
                preY: touchInfo.curY,
                curTime: e.timeStamp,
                preTime: touchInfo.curTime
            }, true)
        }
    }
    const touchEnd = e => {
        if (!e.touches.length && touchInfo.active) {
            dealScrollInfo(touchInfo.speed);
            clearTouchInfo();
        }
    }


    useEffect(() => {
        window.addEventListener('resize', onResize);
        window.addEventListener('touchstart', touchStart, { passive: false });
        window.addEventListener('touchmove', touchMove, { passive: false });
        window.addEventListener('touchend', touchEnd, { passive: false });
        window.addEventListener('mousewheel', onWheel);
        window.addEventListener('scroll', onScroll);
        window.addEventListener('keydown', onKeyDown);
        return () => {
            window.removeEventListener('resize', onResize);
            window.removeEventListener('touchstart', touchStart, { passive: false });
            window.removeEventListener('touchmove', touchMove, { passive: false });
            window.removeEventListener('touchend', touchEnd, { passive: false });
            window.removeEventListener('mousewheel', onWheel);
            window.removeEventListener('scroll', onScroll);
            window.removeEventListener('keydown', onKeyDown);
        }
    })

    const dealScrollInfo = speed => {
        let targetPage = page;
        if (Math.abs(speed) > 1) {
            targetPage = page - Math.ceil((speed) / Math.abs(speed));
        }
        if (targetPage < 0) targetPage = 0;
        if (targetPage > MAX_PAGE) targetPage = MAX_PAGE;
        goPage(targetPage);
    }

    const setTouch = (e, figureSpeed = false) => {
        Object.assign(touchInfo, e);
        if (figureSpeed) {
            touchInfo.speed = (touchInfo.curY - touchInfo.preY) / (touchInfo.curTime - touchInfo.preTime)
        }
    }
    const scrollTo = (targetScroll = 0, deltaDistance, t = new Date().getTime(), preTime, totalTime = ANIME_TIME) => {
        const time = new Date().getTime() - t;
        let deltaTime = 0;
        if (preTime && preTime !== t) deltaTime = time - preTime;
        const scrollY = window.scrollY;
        let currentTargetScroll = scrollY;
        let preF, curF, tSpeed,deltaF;
        if (Math.abs(scrollY - targetScroll) < MIN_SPEED || time > totalTime || Math.floor((targetScroll - scrollY) / Math.abs(targetScroll - scrollY)) !== Math.floor(deltaDistance / Math.abs(deltaDistance))) {
            animationID = window.cancelAnimationFrame(animationID);
            window.scrollTo(0, targetScroll);
            return;
        } else {
            const subValue = deltaDistance;
            const positive = subValue / Math.abs(subValue);
            preF = +Math.cos(Math.PI * (((time - deltaTime) / totalTime)));
            curF = +Math.cos(Math.PI * ((time / totalTime)));
            deltaF=preF-curF;
            tSpeed = Math.abs(deltaDistance) * deltaF;
            if(tSpeed<1) tSpeed=1;
            currentTargetScroll += tSpeed * positive;
        }

        if (!isNaN(currentTargetScroll) && !isNaN(targetScroll) && scrollY !== targetScroll) {
            window.scrollTo(0, currentTargetScroll);
            animationID = window.requestAnimationFrame(() => {
                scrollTo(targetScroll, deltaDistance, t, time, totalTime)
            })
        }
    }
    const goPage = (target, time) => {
        let targetPage = target;
        if (targetPage < 0) targetPage = 0;
        if (targetPage > MAX_PAGE) targetPage = MAX_PAGE;
        setPage(targetPage);
        const targetScroll = pageHeight * targetPage;
        const deltaScroll = Math.abs(targetScroll - window.scrollY);
        const currentTime = new Date().getTime();
        let animeTime = time || ANIME_TIME * deltaScroll / pageHeight;
        scrollTo(targetScroll, (targetScroll - window.scrollY), currentTime, currentTime, animeTime);
    }

    return (
        <>
            {/* 指示器 */}
            <Monitor pageNumber={MAX_PAGE} page={page} scroll={scroll} height={pageHeight} goPage={goPage} />
            {/* 页面 */}
            <Page height={pageHeight} page={page} scroll={scroll} />
        </>
    );

}
const clearTouchInfo = () => {
    touchInfo = {
        preTime: null,
        curTime: null,
        preY: null,
        curY: null,
        oriY: null,
        speed: null,
        oriPage: null,
        active: false
    }
}
const init = () => {
    clearTouchInfo();
    scrollTimer = window.clearTimeout(scrollTimer);
    scrollTimer = window.clearTimeout(scrollToTimer);
}
init();
const getTouchInfo = e => {
    if (!e || !e.touches || !e.touches[0] || !e.touches[0].clientX) {
        throw (new Error('数据错误'))
    }
    return {
        x: e.touches[0].clientX,
        y: e.touches[0].clientY
    }
}
export default App;
